﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data;
using Microsoft.Kinect;
using HCIProject;
using System.IO;
using System.Windows.Threading;

namespace HCIproject
{
    /// <summary>
    /// Interaction logic for PlayWindow.xaml
    /// </summary>
    ///
    public partial class PlayWindow : Window
    {
        #region Ducks
        //constant variables
        int widthPic = 0;
        int heightPic = 0;
        int diffRatio = 0;
        public const int windowWidth = 640;
        public const int windowHeight = 480;
        int x = 0;
        int y = 0;
        int z = 0;
        static string ImagesAdd = "pack://application:,,,/Images/";
        static string AudioAdd = "pack://application:,,,/Audio/";
        DataSet ds = new DataSet();
        DataTable duckTable = new DataTable();      // store the ducks' positions
        DataTable GameConfig = new DataTable();
        string level = "";
        int countKill = 0;
        int playTime = 0;
        DispatcherTimer timer = new DispatcherTimer();
        //V make a list of effective joints (for setting dynamically)
        List<JointType> playJoints = new List<JointType>();
        public PlayWindow(string _level)
        {
            level = _level;
            InitializeComponent();
            DirectoryInfo DI = new DirectoryInfo(Environment.CurrentDirectory);
            string xmlfile = DI.Parent.Parent.FullName.ToString() + "\\File\\" + level + ".xml";
            ds.ReadXml(xmlfile);
            GameConfig = ds.Tables[0];
            // Read playable joints from XML file
            string[] playableJointsXML = GameConfig.Rows[0]["PlayJoint"].ToString().Split(',');
            // Create list of playable joints
            foreach (string j in playableJointsXML)
            {
                if (j.Equals("LF"))
                    playJoints.Add(JointType.FootLeft);
                if (j.Equals("RF"))
                    playJoints.Add(JointType.FootRight);
                if (j.Equals("LH"))
                    playJoints.Add(JointType.HandLeft);
                if (j.Equals("RH"))
                    playJoints.Add(JointType.HandRight);
            }
            duckTable = ds.Tables[1];
            playTime = Convert.ToInt32(GameConfig.Rows[0]["PlayTime"]) * 60;
            for (int i = 0; i < duckTable.Rows.Count; i++)
            {
                setSizeofPic(Convert.ToInt32(duckTable.Rows[i]["size"]));
                Image img = new Image();
                img.Width = widthPic;
                img.Height = heightPic;
                img.Name = duckTable.Rows[i]["id"].ToString();
                this.RegisterName(duckTable.Rows[i]["id"].ToString(), img);
                var uriSource = new Uri(ImagesAdd + "duckBig.png");
                img.Source = new BitmapImage(uriSource);
                mainCanvas.Children.Add(img);
                Canvas.SetLeft(img, Convert.ToInt32(duckTable.Rows[i]["x"]));
                Canvas.SetTop(img, Convert.ToInt32(duckTable.Rows[i]["y"]));
            }
        }
        private void TimerHandeler(Panel counterPanel)
        {

            timer.Tick +=
                delegate(object s, EventArgs args)
                {
                    if (playTime == 0)
                    {
                        if (timer.IsEnabled) timer.Stop();
                        MessageBox.Show("your time is Finished!" + System.Environment.NewLine + "Total ducks you caught from " + GameConfig.Rows[0]["NumberOfDuck"].ToString() + " is: " + countKill);
                    }

                    counterPanel.Children.Clear();
                    counterPanel.Children.Add(new TextBlock
                    {

                        Text = "your remainig time: " + playTime--.ToString(),
                        HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
                        FontSize = 16
                    });
                };

            timer.Interval = new TimeSpan(0, 0, 1); // one second
            timer.Start();

        }
        private void Window_Loaded_1(object sender, RoutedEventArgs e)
        {
            GameStart();
        }
        private void GameStart()
        {
            DirectoryInfo DI = new DirectoryInfo(Environment.CurrentDirectory);
            string Audio = DI.Parent.Parent.FullName.ToString() + "\\Audio\\TheDuckSong.mp3";

            mediaplayer.Source = new Uri(Audio);
            mediaplayer.Play();
            TimerHandeler(TimerPanel);

            try
            {
                //listen to any status change for Kinects
                KinectSensor.KinectSensors.StatusChanged += Kinects_StatusChanged;
                //loop through all the Kinects attached to this PC, and start the first that is connected without an error.
                foreach (KinectSensor kinect in KinectSensor.KinectSensors)
                {
                    if (kinect.Status == KinectStatus.Connected)
                    {
                        kinectSensor = kinect;
                        break;
                    }
                }
                if (KinectSensor.KinectSensors.Count == 0)
                    MessageBox.Show("No Kinect found");
                else
                {
                    Initialize();

                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private void Window_MouseMove_1(object sender, MouseEventArgs e)
        {
            Point p = Mouse.GetPosition(Application.Current.MainWindow);
            labelxy.Content = "X= " + p.X + ", Y= " + p.Y;
            Image image;
            for (int i = 0; i < duckTable.Rows.Count; i++)
            {
                if (Math.Abs(p.X - Convert.ToInt32(duckTable.Rows[i]["x"]) - widthPic / 2) < diffRatio &&
                    Math.Abs(p.Y - Convert.ToInt32(duckTable.Rows[i]["y"]) - heightPic / 2) < diffRatio)
                {
                    image = (Image)mainGrid.FindName(duckTable.Rows[i]["id"].ToString());
                    if (image.Visibility == System.Windows.Visibility.Visible)
                    {
                        DirectoryInfo DI = new DirectoryInfo(Environment.CurrentDirectory);
                        string Audio = DI.Parent.Parent.FullName.ToString() + "\\Audio\\KillDuck.mp3";
                        duckKill.Source = new Uri(Audio);
                        duckKill.Play();

                        countKill++;

                        if (countKill == Convert.ToInt32(GameConfig.Rows[0]["NumberOfDuck"]))
                        {
                            string finish = (Convert.ToInt32(GameConfig.Rows[0]["PlayTime"]) * 60 - playTime).ToString();
                            timer.Stop();
                            MessageBoxResult result = MessageBox.Show("Good Job" + System.Environment.NewLine + "you caught all the ducks in: " + finish + " seconds" + System.Environment.NewLine +
                                "Do you want to play the game again?", "Finish", MessageBoxButton.YesNo, MessageBoxImage.Question
                                );
                            if (result == MessageBoxResult.Yes)
                            {
                                kinectSensor.Stop();
                                PlayWindow pp = new PlayWindow("Easy");
                                pp.Show();
                                pp.Initialize();
                                this.Close();
                            }
                            else
                            {
                                MainWindow mw = new MainWindow();
                                mw.Show();
                                this.Close();
                            }
                        }
                    }
                    image.Visibility = System.Windows.Visibility.Hidden;

                }
            }
        }
        private void Window_MouseDown_1(object sender, MouseButtonEventArgs e)
        {
            //Image image;
            //Point p = Mouse.GetPosition(Application.Current.MainWindow);
            //for (int i = 0; i < duckTable.Rows.Count; i++)
            //{
            //    if (Math.Abs(p.X - Convert.ToInt32(duckTable.Rows[i]["x"]) - widthPic / 2) < diffRatio &&
            //        Math.Abs(p.Y - Convert.ToInt32(duckTable.Rows[i]["y"]) - heightPic / 2) < diffRatio)
            //    {
            //        image = (Image)mainGrid.FindName(duckTable.Rows[i]["id"].ToString());

            //        if (image.Visibility == System.Windows.Visibility.Visible)
            //        {
            //            DirectoryInfo DI = new DirectoryInfo(Environment.CurrentDirectory);
            //            string Audio = DI.Parent.Parent.FullName.ToString() + "\\Audio\\KillDuck.mp3";

            //            duckKill.Source = new Uri(Audio);
            //            duckKill.Play();
            //            countKill++;
            //            if (countKill == Convert.ToInt32(GameConfig.Rows[0]["NumberOfDuck"]))
            //            {
            //                string finish = (Convert.ToInt32(GameConfig.Rows[0]["PlayTime"]) * 60 - playTime).ToString();
            //                timer.Stop();
            //                MessageBox.Show("Good Job" + System.Environment.NewLine + "you caught all the ducks in: " + finish + " seconds");


            //            }
            //        }
            //        image.Visibility = System.Windows.Visibility.Hidden;


            //    }
            // }
        }
        void RegisterImage(string imgName, Image img)
        {
            if ((Image)this.FindName(imgName) != null)
                this.UnregisterName(imgName);
            this.RegisterName(imgName, img);
        }
        void setSizeofPic(int Type)
        {
            if (Type == Convert.ToInt32(ImageTypes.Big))
            { widthPic = 100; heightPic = 100; diffRatio = 35; }
            else if (Type == Convert.ToInt32(ImageTypes.Medium))
            { widthPic = 50; heightPic = 50; diffRatio = 12; }
            else if (Type == Convert.ToInt32(ImageTypes.Small))
            { widthPic = 30; heightPic = 30; diffRatio = 6; }

        }
        #endregion Ducks

        #region Kinect
        KinectSensor kinectSensor;

        readonly ColorStreamManager colorManager = new ColorStreamManager();
        readonly DepthStreamManager depthManager = new DepthStreamManager();
        SkeletonDisplayManager skeletonDisplayManager;
        Skeleton[] skeletons;
        readonly ContextTracker contextTracker = new ContextTracker();
        void Kinects_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case KinectStatus.Connected:
                    if (kinectSensor == null)
                    {
                        kinectSensor = e.Sensor;
                        Initialize();
                    }
                    break;
                case KinectStatus.Disconnected:
                    if (kinectSensor == e.Sensor)
                    {
                        Clean();
                        MessageBox.Show("Kinect was disconnected");
                    }
                    break;
                case KinectStatus.NotReady:
                    break;
                case KinectStatus.NotPowered:
                    if (kinectSensor == e.Sensor)
                    {
                        Clean();
                        MessageBox.Show("Kinect is no more powered");
                    }
                    break;
                default:
                    MessageBox.Show("Unhandled Status: " + e.Status);
                    break;
            }
        }
        private void Initialize()
        {
            if (kinectSensor == null)
                return;

            kinectSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
            kinectSensor.ColorFrameReady += kinectRuntime_ColorFrameReady;

            kinectSensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
            kinectSensor.DepthFrameReady += kinectSensor_DepthFrameReady;

            kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters
            {
                Smoothing = 0.5f,
                Correction = 0.5f,
                Prediction = 0.5f,
                JitterRadius = 0.05f,
                MaxDeviationRadius = 0.04f
            });
            kinectSensor.SkeletonFrameReady += kinectRuntime_SkeletonFrameReady;

            kinectSensor.Start();

            skeletonDisplayManager = new SkeletonDisplayManager(kinectSensor, kinectCanvas);
            kinectDisplay.DataContext = colorManager;   // if we want to display Color Stream
            //kinectDisplay.DataContext = depthManager;   // if we want to display Depth Stream
        }
        private void kinectRuntime_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (var frame = e.OpenColorImageFrame())
            {
                if (frame == null)
                    return;

                colorManager.Update(frame);
            }
        }
        void kinectSensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (var frame = e.OpenDepthImageFrame())
            {
                if (frame == null)
                    return;

                depthManager.Update(frame);
            }
        }
        void kinectRuntime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                    return;

                frame.GetSkeletons(ref skeletons);

                if (skeletons.All(s => s.TrackingState == SkeletonTrackingState.NotTracked))
                    return;

                ProcessFrame(frame);




            }
        }
        void ProcessFrame(SkeletonFrame frame)
        {

            Dictionary<int, string> stabilities = new Dictionary<int, string>();
            foreach (var skeleton in frame.GetSkeletons())
            {
                if (skeleton.TrackingState != SkeletonTrackingState.Tracked)
                    continue;

                contextTracker.Add(skeleton.Position.ToVector3(), skeleton.TrackingId);
                stabilities.Add(skeleton.TrackingId, contextTracker.IsStableRelativeToCurrentSpeed(skeleton.TrackingId) ? "Stable" : "Non stable");
                if (!contextTracker.IsStableRelativeToCurrentSpeed(skeleton.TrackingId))
                    continue;
                Image image;
                foreach (Joint joint in skeleton.Joints)
                {
                    if (joint.TrackingState != JointTrackingState.Tracked)
                        continue;
                    //if ((joint.JointType == JointType.FootLeft) || (joint.JointType == JointType.FootRight)) ;// || (joint.JointType == JointType.FootLeft))
                    if (playJoints.Contains(joint.JointType))
                    {
                        var colorPoint = kinectSensor.CoordinateMapper.MapSkeletonPointToColorPoint(joint.Position, kinectSensor.ColorStream.Format);
                        x = Convert.ToInt32(colorPoint.X);// * 800 / 640);// * kinectCanvas.ActualWidth));
                        y = Convert.ToInt32(colorPoint.Y);// * 600 / 480);// * kinectCanvas.ActualHeight));
                        var depthPoint = kinectSensor.CoordinateMapper.MapSkeletonPointToDepthPoint(joint.Position, kinectSensor.DepthStream.Format);
                        z = Convert.ToInt32(depthPoint.Depth);
                        // Consider using depthPoint for X and Y also

                        // Console.WriteLine(x + " + " + y);
                        labelxy.Content = "X= " + x + ", Y= " + y;

                        // compare with duck's position

                        for (int i = 0; i < duckTable.Rows.Count; i++)
                        {
                            if (Math.Abs(x - Convert.ToInt32(duckTable.Rows[i]["x"]) - widthPic / 2) < diffRatio &&
                                Math.Abs(y - Convert.ToInt32(duckTable.Rows[i]["y"]) - heightPic / 2) < diffRatio &&
                                (Math.Abs(z - Convert.ToInt32(duckTable.Rows[i]["z"])) < diffRatio))
                            {
                                image = (Image)mainGrid.FindName(duckTable.Rows[i]["id"].ToString());
                                if (image.Visibility == System.Windows.Visibility.Visible)
                                {
                                    DirectoryInfo DI = new DirectoryInfo(Environment.CurrentDirectory);
                                    string Audio = DI.Parent.Parent.FullName.ToString() + "\\Audio\\KillDuck.mp3";
                                    duckKill.Source = new Uri(Audio);
                                    duckKill.Play();
                                    countKill++;
                                    if (countKill == Convert.ToInt32(GameConfig.Rows[0]["NumberOfDuck"]))
                                    {
                                        string finish = (Convert.ToInt32(GameConfig.Rows[0]["PlayTime"]) * 60 - playTime).ToString();
                                        timer.Stop();
                                        string s = "Good Job" +
                                                    System.Environment.NewLine +
                                                    "you caught all the ducks in: " +
                                                    finish +
                                                    " seconds" +
                                                    System.Environment.NewLine +
                                                    "Do you want to play the game again?";
                                        MessageBoxResult result = MessageBox.Show(s, "Finish", MessageBoxButton.YesNo, MessageBoxImage.Question);
                                        if (result == MessageBoxResult.Yes)
                                        {
                                            levelMenu lv = new levelMenu();
                                            lv.Show();
                                            this.Close();
                                        }
                                        else
                                        {
                                            MainWindow mw = new MainWindow();
                                            mw.Show();
                                            this.Close();
                                        }


                                    }
                                }
                                image.Visibility = System.Windows.Visibility.Hidden;


                            }
                        }
                    }
                }
            }

            //skeletonDisplayManager.Draw(frame.Skeletons, seatedMode.IsChecked == true);
            skeletonDisplayManager.Draw(frame.GetSkeletons(), false);
            //stabilitiesList.ItemsSource = stabilities;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                Clean();
                this.Close();
            }
            catch
            {
                // do nothing
            }
        }

        private void Clean()
        {
            if (kinectSensor != null)
            {
                kinectSensor.DepthFrameReady -= kinectSensor_DepthFrameReady;
                kinectSensor.SkeletonFrameReady -= kinectRuntime_SkeletonFrameReady;
                kinectSensor.ColorFrameReady -= kinectRuntime_ColorFrameReady;
                kinectSensor.Stop();
                //kinectSensor = null;
            }
        }


        #endregion Kinect
    }
}
